package bancosys.tec.security.impl.web.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.web.context.support.WebApplicationContextUtils;

import bancosys.tec.security.SecurityManager;
import bancosys.tec.security.impl.web.WebSecurityContext;

/**
 * Servlet abstrato de segurança. Configurações:<br>
 * <table>
 * <tr>
 * <td>securityManager</td>
 * <td>BeanID do security manager no spring.</td>
 * </tr>
 * </table>
 * 
 * @created 31/03/2008
 * @author Gustavo Almeida
 */
public abstract class SecurityServlet extends HttpServlet {

    public static final String SECURITY_MANAGER_BEAN_ID = "securityManager";

    private String securityManagerBeanId;

    private volatile SecurityManager securityManager;

    private BeanFactory beanFactory;

    /**
     * Inicializa o servlet com seus parâmetros de configuração.
     * 
     * @throws ServletException veja {@link HttpServlet}
     */
    @Override
    public void init() throws ServletException {
        super.init();
        this.securityManagerBeanId = this.getNotNull(this.getServletConfig().getInitParameter(SECURITY_MANAGER_BEAN_ID), "securityManager");
    }

    /**
     * @return {@link BeanFactory}
     * @deprecated Servlets com dependências no spring deveriam ser instanciados no spring e utilizados através do DelegatingServletProxy
     */
    @Deprecated
    protected final BeanFactory getBeanFactory() {
        if (this.beanFactory == null) {
            this.beanFactory = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
            if (this.beanFactory instanceof ConfigurableApplicationContext) {
                ((ConfigurableApplicationContext) this.beanFactory).addApplicationListener(new ApplicationListener() {

                    public void onApplicationEvent(ApplicationEvent event) {
                        if (event instanceof ApplicationContextEvent) {
                            SecurityServlet.this.securityManager = null;
                        }
                    }
                });
            }
        }
        return this.beanFactory;
    }

    /**
     * Envia headers que impedem que o browser faça cache da página enviada.
     * 
     * @param response resposta http.
     */
    protected void setNoCacheHeaders(HttpServletResponse response) {
        response.addHeader("Pragma", "No-Cache");
        response.addHeader("Cache-Control", "no-cache");
        response.addHeader("Cache-Control", "no-store");
        response.addHeader("Cache-Control", "must-revalidate");
        response.addHeader("Expires", "Thu, 01 Jan 1970 00:00:00 GMT");
    }

    /**
     * Devolve o securityManager.
     * 
     * @return o securityManager.
     */
    @SuppressWarnings("unchecked")
    public SecurityManager<WebSecurityContext> getSecurityManager() {
        if (this.securityManager == null) {
            this.securityManager = (SecurityManager<WebSecurityContext>) this.getBeanFactory().getBean(this.securityManagerBeanId);
        }
        return this.securityManager;
    }

    /**
     * Executa forward para o uri indicado.
     * 
     * @param request request http
     * @param response response http
     * @param uri uri para onde o forward deve ser executado.
     * @throws ServletException veja {@link RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)}
     * @throws IOException veja {@link RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)}
     */
    protected void forward(HttpServletRequest request, HttpServletResponse response, String uri) throws ServletException, IOException {
        RequestDispatcher dispatcher = request.getRequestDispatcher(uri);
        dispatcher.forward(request, response);
    }

    /**
     * Devolve str1 se essa for diferente de <code>null</code>, senão devolve str2.
     * 
     * @param str1 string 1
     * @param str2 string 2
     * @return str1 se essa for diferente de <code>null</code>, senão devolve str2.
     */
    protected String getNotNull(String str1, String str2) {
        return (str1 != null) ? str1 : str2;
    }

}
